/* 
 * File:   OperacionCargaChunksModificados.cpp
 * Author: nahuel
 * 
 * Created on June 23, 2013, 3:58 PM
 */

#include "client_OperacionCargaChunksModificados.h"
#include "common_NumeroUtils.h"
#include "common_FileUtils.h"
#include "common_Codec.h"
#include "common_Logger.h"

OperacionCargaChunksModificados::OperacionCargaChunksModificados(uint32_t pToken,
                                      FileServiceProxy* pFileService,
                                      Repositorio* pRepositorio, 
                                      const string &pNombreArchivo)
                                : Operacion (pToken) {    
    _nombreArchivo = pNombreArchivo;
    _repositorio = pRepositorio;
    _fileService = pFileService;    
}

void OperacionCargaChunksModificados::getChunkDelServidor(const uint32_t &pNumeroChunk) {    
    _fileService->GetFileChunk(getId(), _nombreArchivo, pNumeroChunk);
}

void OperacionCargaChunksModificados::procesarRespuesta(vector<string> &pRespuesta) {
    /* Formato respuesta:
     * <token>;<recurso>;<accion>;<args>
     */

    if (FileServiceConstants::GET_MOD_CHUNKS_LIST == pRespuesta[2]) {
        this->manejarRespuestaGetChunksListDelServidor(pRespuesta);
    } else if (FileServiceConstants::GET_MOD_CHUNK == pRespuesta[2]) {
        this->manejarRespuestaGetChunkDelServidor(pRespuesta);
    }
}

void OperacionCargaChunksModificados::manejarRespuestaGetChunkDelServidor (vector<string> &pRespuesta) {
    /* Formato de la respuesta:
     * 
     * <token>(0);<recurso>(1);<accion>(2);<nombre_archivo>(3);<nro_chunk>(4);<chunk>(5)
     */
    RepoItem *item = _repositorio->GetRepoItemByFilename(_nombreArchivo);
    std::string nombreArchivo = pRespuesta[3];

    if (NULL == item)
    {
        throw "El archivo al que hace referencia la notficacion del servidor no posee archivo asociado en el repositorio local. Archivo " +  nombreArchivo;
    }

    // Guardo el chunk y actualizo el repositorio.
    int32_t numeroChunk = NumeroUtils::ParseInt32(pRespuesta[4]);
    this->GuardarChunkEnArchivo(item->GetRutaCompletaArchivo(), pRespuesta[5], numeroChunk);
    item->ActualizarHash(numeroChunk, pRespuesta[6]);
}

void OperacionCargaChunksModificados::manejarRespuestaGetChunksListDelServidor(vector<string> &pRespuesta) {
    /* El archivo existe y el hash solicitado corresponde con el archivo
     * indicado.  se comunica el chunk.
     * 
     * Formato de la respuesta:
     * 
     * <token>(0);<recurso>(1);<accion>(2);
     *      <nombre_archivo>   (3)
     * ;    <nro chunk>        (4)
     *          .
     *          .
     *          .
     * ;    <nro chunk>        (n)
     * 
     */    
    try
    {
        for(unsigned int i = 4; i < pRespuesta.size(); i++) {
            int32_t nroChunk = NumeroUtils::ParseInt32(pRespuesta[i]);
            getChunkDelServidor(nroChunk);
        }
    }
    catch (const string &ex)
    {        
        Logger::LogMessage("No se pudo actualizar el archivo " + _nombreArchivo
                            + ". " + ex
        );
        this->setFinalizada(true);
    }
}

void OperacionCargaChunksModificados::GuardarChunkEnArchivo (const string& pNombreArchivo, 
                                                             const string &pChunk,
                                                             int32_t numeroChunk) {
    // Decodifico el chunk.
    Codec codec;
    uint8_t* chunk = NULL;
    uint32_t longitudChunk = 0;
    
    codec.decodificar(chunk, longitudChunk, pChunk);    
    
    // Guardo el chunk en el archivo indicado.
    if (longitudChunk > 0)
    {
        FileUtils fileUtils;
        fileUtils.WriteChunk(pNombreArchivo, (const uint8_t*)pChunk.c_str(), 
                             longitudChunk, numeroChunk);
    }    
}

void OperacionCargaChunksModificados::ejecutar() {
    
}

OperacionCargaChunksModificados::~OperacionCargaChunksModificados() {}